package com.threeti.mecool.core.domain.model.project;

import com.threeti.mecool.core.domain.model.acl.OrgnizationEmployee;
import com.threeti.mecool.core.domain.model.acl.User;
import com.threeti.mecool.core.infrastructure.persistence.acl.UserRepository;
import com.threeti.mecool.framework.domain.support.DefaultDomainEntity;
import com.threeti.mecool.framework.util.Lists;
import com.threeti.mecool.framework.util.Maps;
import com.threeti.mecool.framework.util.Sets;
import com.threeti.mecool.legacy.domain.model.basicdata.CustomerLegacy;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Configurable;

import javax.annotation.Resource;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * 项目
 *
 * @author Jay Meng
 */
@Configurable
@Entity
@Table(name = "DM_PROJECT")
public class Project extends DefaultDomainEntity {

    @Column(nullable = false, unique = true)
    private String code;

    @Column(nullable = false)
    private String name;

    @ManyToOne(optional = false)
    private CustomerLegacy customer;

    @Column(nullable = false)
    private Long managerEmpId;//jay:采用弱化设计  替代了@OneToOne(optional = false, mappedBy = "project", cascade = { CascadeType.ALL }),or leads conflict with one2many mapping latter
    private String orgCode;

    @ManyToOne(optional = false)
    @JoinColumn(name = "USER_ID")
    private User user;

    @ManyToOne(optional = false)
    private ProjectCategory category;

    @Enumerated(EnumType.ORDINAL)
    private ProjectStatus status = ProjectStatus.INACTIVE;

    private Date startDate = new Date();

    private Date endDate = new Date();

    private String description;

    @OneToOne(mappedBy = "project", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private ProjectSellingUpload sellingUpload;

    @OneToMany(mappedBy = "project", cascade = {CascadeType.ALL})
//jay:orphan remove can't be used,because batch refresh of the emps tree is allowed(by using setter)
    //@OneToMany(mappedBy = "project", cascade = { CascadeType.ALL }, fetch=FetchType.EAGER)//jay:egaer strategy
    //@Fetch(FetchMode.SUBSELECT)
    private List<ProjectEmployee> participatedEmployees = Lists.newArrayList();

    @OneToMany(mappedBy = "project", cascade = {CascadeType.ALL})
//jay:orphan remove can't be used,because batch refresh of the emps tree is allowed(by using setter)
    //@OneToMany(mappedBy = "project", cascade = { CascadeType.ALL }, fetch=FetchType.EAGER)//jay:egaer strategy
    //@Fetch(FetchMode.SUBSELECT)
    private List<ProjectSalesPromoter> participatedSalesPromoters = Lists.newArrayList();

    @Enumerated(EnumType.ORDINAL)
    private ProjectProductCollectionType productsCollectionType;

    @OneToMany(mappedBy = "project", cascade = {CascadeType.ALL})
//jay:orphan remove can't be used,because batch refresh of the products tree is allowed(by using setter)
    private List<ProjectProduct> productsNeedToBeCollected = Lists.newArrayList();

    @Resource
    @Transient
    private UserRepository userRepository;

    public Project(User user, String code, String orgCode, String name, CustomerLegacy customer, ProjectEmployee projectManager, ProjectCategory category) {
        super();
        this.user = user;
        this.code = code;
        this.name = name;
        this.customer = customer;
        this.managerEmpId = projectManager.getEmpId();
        this.orgCode = orgCode;

        //创建项目时自动成为首位项目成员，即项目经理(负责人)->
        projectManager.setProject(this);
        this.getParticipatedEmployees().add(projectManager);
        //<-

        this.category = category;
        this.status = ProjectStatus.ACTIVE;//默认激活
    }

    /**
     * 快速创建Project的alternative method
     */
    public static Project newProject(User user, Project halfBuildedProject, OrgnizationEmployee orgEmployee) {
        ProjectEmployee projManager = new ProjectEmployee(null, orgEmployee.getEmpId(), orgEmployee.getName(), "项目负责人", ProjectEmployeeRankType.LEVEL_MANAGEMENT);

        //return new Project(user, halfBuildedProject.getCode(), halfBuildedProject.getName(), halfBuildedProject.getCustomer(), projManager, halfBuildedProject.getCategory());

        halfBuildedProject.setUser(user);
        halfBuildedProject.setManagerEmpId(projManager.getEmpId());
        halfBuildedProject.setOrgCode(orgEmployee.getOrgCode());
        projManager.setProject(halfBuildedProject);
        halfBuildedProject.getParticipatedEmployees().add(projManager);
        halfBuildedProject.setStatus(ProjectStatus.ACTIVE);//默认激活

        return halfBuildedProject;
    }

    /**
     * 项目创建人(用户)
     */
    public User getUser() {
        return user;
    }

    /**
     * 项目编号
     */
    public String getCode() {
        return code;
    }

    /**
     * 项目名称
     */
    public String getName() {
        return name;
    }

    /**
     * 客户名称
     */
    public CustomerLegacy getCustomer() {
        return customer;
    }

    /**
     * 项目负责人(通常即指项目经理)
     */
    public Long getManagerEmpId() {
        return managerEmpId;
    }

    /**
     * 项目所在的组织机构Code(项目所在的组织机构即指项目经理所在的组织机构)
     */
    public String getOrgCode() {
        return orgCode;
    }

    /**
     * 项目开始日期
     */
    public Date getStartDate() {
        return startDate;
    }

    /**
     * 项目结束日期
     */
    public Date getEndDate() {
        return endDate;
    }

    /**
     * 项目类型
     */
    public ProjectCategory getCategory() {
        return category;
    }

    /**
     * 项目状态
     */
    public ProjectStatus getStatus() {
        return status;
    }

    /**
     * 项目描述
     */
    public String getDescription() {
        return description;
    }

    /**
     * 项目采集项采集类别
     */
    public ProjectProductCollectionType getProductsCollectionType() {
        return productsCollectionType;
    }

    /**
     * 取得参于项目的所有员工
     */
    public List<ProjectEmployee> getParticipatedEmployees() {
        return participatedEmployees;
    }

    /**
     * 取得参于项目的所有促销员
     */
    public List<ProjectSalesPromoter> getParticipatedSalesPromoters() {
        return participatedSalesPromoters;
    }

    /**
     * 取得参于项目的指定员工
     */
    public ProjectEmployee getParticipatedEmployeeBy(Long empId) {
        for (ProjectEmployee projEmp : participatedEmployees) {
            if (projEmp != null && empId.equals(projEmp.getEmpId())) return projEmp;
        }
        return null;
    }

//  /** 添加项目员工(该方法暂时无法适用于Tree的整树更新，因此已废弃)  */
//  public Project addParticipatedEmployee(ProjectEmployee participatedProjEmp) {
//    participatedProjEmp.setProject(this);
//    participatedEmployees.add(participatedProjEmp);
//    return this;
//  }

    /**
     * 取得项目采集项
     */
    public List<ProjectProduct> getProductsNeedToBeCollected() {
        return productsNeedToBeCollected;
    }

    /**
     * 从项目采集项中取得(特定客户的)品类Code和品牌Code集合
     *
     * @return result Map:key "brandCategoryCodes"代表品类Code集合, key "brandCodes"代表品牌Code集合
     */
    public Map<String, Set<String>> getCollectingProductsBrandCategoriesCodes() {
        List<ProjectProduct> projProds = getProductsNeedToBeCollected();
        Map<String, Set<String>> rtnMap = Maps.newHashMap();

        Set<String> brandCategoryCodes = Sets.newHashSet();
        Set<String> brandCodes = Sets.newHashSet();
        for (ProjectProduct projProd : projProds) {
            if (projProd.getBrand() != null && StringUtils.isNotBlank(projProd.getBrand().getCategoryCode()))
                brandCategoryCodes.add(projProd.getBrand().getCategoryCode());
            brandCodes.add(projProd.getBrand().getCode());
        }

        rtnMap.put("brandCategoryCodes", brandCategoryCodes);
        rtnMap.put("brandCodes", brandCodes);
        return rtnMap;
    }

    public ProjectSellingUpload getSellingUpload() {
        return sellingUpload;
    }

    /**
     * 刷新项目采集项
     */
    public void setProductsNeedToBeCollected(List<ProjectProduct> productsNeedToBeCollected) {
        this.productsNeedToBeCollected = productsNeedToBeCollected;
    }

    /**
     * 刷新项目员工(树)
     */
    public void setParticipatedEmployees(List<ProjectEmployee> participatedEmployees) {
        this.participatedEmployees = participatedEmployees;
    }

    /**
     * 刷新项目促销员
     */
    public void setParticipatedSalesPromoters(List<ProjectSalesPromoter> participatedSalesPromoters) {
        this.participatedSalesPromoters = participatedSalesPromoters;
    }

    @Override
    public String toString() {
        return "Project [user=" + user + ", code=" + code + ", name=" + name + ", customer=" + customer + ", managerEmpId="
                + managerEmpId + ", category=" + category + ", status=" + status + ", startDate=" + startDate + ", endDate="
                + endDate + ", description=" + description + "]";
    }

    public Project() {
        super();
    }

    public void setUser(User user) {
        this.user = user;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public void setProductsCollectionType(ProjectProductCollectionType productsCollectionType) {
        this.productsCollectionType = productsCollectionType;
    }

    public void setStartDate(Date startDate) {
        this.startDate = startDate;
    }

    public void setEndDate(Date endDate) {
        this.endDate = endDate;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setCustomer(CustomerLegacy customer) {
        this.customer = customer;
    }

    public void setManagerEmpId(Long managerEmpId) {
        this.managerEmpId = managerEmpId;
    }

    public void setCategory(ProjectCategory category) {
        this.category = category;
    }

    public void setStatus(ProjectStatus status) {
        this.status = status;
    }

    public void setOrgCode(String orgCode) {
        this.orgCode = orgCode;
    }

    public String getManagerName() {
        User manager = userRepository.findByEmployeeEmpId(managerEmpId);
        return manager != null ? manager.getDisplayName() : "";
    }

    public void setSellingUpload(ProjectSellingUpload sellingUpload) {
        this.sellingUpload = sellingUpload;
    }
}
